Rust 作為一個系統編程語言,因其高效能和內建的記憶體安全性,逐漸在各領域獲得了廣泛應用,尤其是在 Web 開發中。雖然 Rust 本身並不是專門為 Web 開發設計的語言,但隨著許多高效能 Web 框架的出現,Rust 成為了一個極具潛力的後端 Web 開發語言。本篇文章將帶你認識 Rust 中的 Web 框架:Actix
Actix 是一個非常高效且自由度高的 Rust Web 框架,其基於 Actor 模型構建,簡單來說 Actix 提供了非同步的支持,使得它在大量並行要求的情境下能夠有出色的表現,它也是 Rust 生態系統中性能最高的 Web 框架之一。
首先讓我們建立一個 web 專用的專案 rust-web
:
cargo new rust-web
cd rust-web
然後我們需要引入 Actix套件,修改 Cargo.toml
:
[dependencies]
actix-web = "4"
接下來, main.rs
建立下面使用 Actix 開發的簡單 Web 應用程式:
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
// 定義一個簡單的處理器,處理 HTTP 請求並回傳 "Hello from Actix!" 作為回應
async fn greet() -> impl Responder {
// 回傳一個 HTTP 200 OK 狀態的回應,內容為 "Hello from Actix!"
HttpResponse::Ok().body("Hello from Actix!")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// 創建一個 Actix 伺服器
HttpServer::new(|| {
// 使用 App::new() 創建一個新的應用程式,並設置路由
// 當收到 GET 請求到 "/" 路徑時,執行 `greet` 處理器
App::new()
.route("/", web::get().to(greet))
})
// 將伺服器綁定到本地的 127.0.0.1 地址與 8080 埠號
.bind("127.0.0.1:8080")?
// 啟動伺服器並開始處理請求
.run()
.await
}
async fn
:async
關鍵字表示這是一個非同步函數,它可以在不阻塞主執行緒的情況下執行。這樣能夠提高伺服器處理多個併發請求的能力。greet 函數
:這是一個簡單的處理器,用來處理 HTTP 請求並返回一個 HTTP 回應。這裡我們使用 HttpResponse::Ok() 表示回應狀態為 200(成功),並在回應的主體中返回字串 "Hello from Actix!"。impl Responder
:這是一個特徵,表示 greet 函數的返回值可以用來回應 HTTP 請求。/
的 GET 請求,並返回一個簡單的 HTTP 回應。#[actix_web::main]
:這是 Actix 的一個特別屬性,它將函數標記為 Actix Web 的非同步主函數,讓程式能夠進行非同步運行。HttpServer::new
:創建一個新的 HTTP 伺服器。這個伺服器會接受一個閉包,並通過 App::new()
來設定應用程式,允許我們設置路由、處理器和中間件。App::new()
:每個 Actix 應用程式都是通過 App::new()
創建的。這裡我們使用 route()
方法來定義當有 GET 請求發送到 / 路徑時,會呼叫我們之前定義的 greet 處理器。run()
和 await
:run()
啟動伺服器,並開始接收請求。await
用來非同步地等待伺服器運行的完成。接下來我們執行主程式
cargo run
就可以從瀏覽器看到 http://localhost:8080 開啟了 actix
網頁,如下所示:
Actix 不僅可以用來回傳純文字的 HTTP 回應,還可以輕鬆地將 HTML 頁面作為回應內容。這在需要動態生成頁面或渲染視圖時非常有用。Actix 支援多種模板引擎,這裡我們使用 Tera 模板引擎來展示如何回傳 HTML。
首先,我們需要在 Cargo.toml
文件中添加 Tera 和 Actix-web 的模板依賴:
[dependencies]
actix-web = "4"
tera = "1.17"
然後,執行以下指令來更新並安裝依賴:
cargo build
接下來,我們需要在專案目錄中創建一個資料夾來存放模板文件。可以在專案的根目錄下建立一個 templates
資料夾,並在其中添加一個名為 index.html
的模板文件:
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Actix + Tera Example</title>
</head>
<body>
<h1>Hello from Actix using Tera!</h1>
<p>Welcome, {{ name }}!</p>
</body>
</html>
這個模板文件簡單地顯示了一個歡迎訊息,並允許我們動態插入一個 name
變數。
main.rs
來渲染模板現在我們可以修改 main.rs
來渲染這個模板。首先需要引入 Tera 模板引擎相關的模組,然後設置路由來回傳 HTML:
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use tera::{Tera, Context};
// 定義一個處理器來渲染模板
async fn greet_with_template(tmpl: web::Data<Tera>) -> impl Responder {
// 創建一個模板上下文,用來傳遞變數到模板中
let mut ctx = Context::new();
ctx.insert("name", "Actix User"); // 插入名為 "name" 的變數,值為 "Actix User"
// 渲染模板並回傳 HTML
// 使用 tmpl.render() 方法渲染模板 "index.html",若渲染失敗則回傳錯誤訊息
let rendered = tmpl.render("index.html", &ctx).unwrap_or_else(|_| {
"Error rendering template".to_string()
});
// 使用 HttpResponse 回傳渲染結果,並設定回應的內容類型為 HTML
HttpResponse::Ok().content_type("text/html").body(rendered)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// 初始化 Tera 模板引擎,並指定模板的路徑為 "templates/**/*"
let tera = Tera::new("templates/**/*").unwrap(); // 加載 templates 資料夾中的所有模板文件
// 創建並啟動 Actix Web 伺服器
HttpServer::new(move || {
App::new()
// 傳遞 Tera 模板引擎的 Data 給 Actix 應用
.app_data(web::Data::new(tera.clone()))
// 定義路由,當訪問 "/" 路徑時,呼叫 greet_with_template 來渲染模板
.route("/", web::get().to(greet_with_template))
})
// 將伺服器綁定到本地 IP 127.0.0.1,埠號為 8080
.bind("127.0.0.1:8080")?
// 啟動伺服器,並非同步地等待伺服器運行
.run()
.await
}
Tera::new()
來加載 templates
資料夾中的所有模板文件。name
的變數,值為 "Actix User"
,然後會在 index.html
中進行顯示。render
方法用來渲染模板,將上下文中的變數插入到對應的模板位置,並返回一個 HTML 字串。一切準備就緒後,我們可以執行專案:
cargo run
在瀏覽器中訪問 http://localhost:8080
,你將看到以下畫面,HTML 模板已成功渲染:
Hello from Actix using Tera!
Welcome, Actix User!
實際瀏覽器畫面如下:
如果想要讓用戶透過 URL 動態傳遞參數,我們可以修改處理器來接受 name
參數:
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use tera::{Tera, Context};
// 定義一個處理器來渲染模板,接受動態的 `name` 參數
// `name` 是從 URL 中動態傳入的路徑參數
async fn greet_with_template(tmpl: web::Data<Tera>, name: web::Path<String>) -> impl Responder {
// 創建模板上下文,將變數傳遞給模板使用
let mut ctx = Context::new();
// 從 `name` 參數中取出值,並插入到模板上下文中
ctx.insert("name", &name.into_inner());
// 使用模板引擎渲染指定的 `index.html` 模板,並將上下文插入到模板中
// 如果渲染失敗,則回傳 "Error rendering template"
let rendered = tmpl.render("index.html", &ctx).unwrap_or_else(|_| {
"Error rendering template".to_string()
});
// 回傳渲染結果,並設定回應的內容類型為 HTML
HttpResponse::Ok().content_type("text/html").body(rendered)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// 初始化 Tera 模板引擎,指定模板文件路徑為 "templates/**/*"
let tera = Tera::new("templates/**/*").unwrap();
// 創建並啟動 HTTP 伺服器
HttpServer::new(move || {
// 新建一個 Actix 應用程式,並將 Tera 模板引擎傳遞進去
App::new()
// 將 Tera 引擎資料傳遞給應用程式以供後續使用
.app_data(web::Data::new(tera.clone()))
// 設定動態路由,當訪問 `/{name}` 路徑時,呼叫 `greet_with_template` 處理器
.route("/{name}", web::get().to(greet_with_template))
})
// 綁定伺服器到本地 IP 127.0.0.1 和埠號 8080
.bind("127.0.0.1:8080")?
// 啟動伺服器並非同步等待運行
.run()
.await
}
現在訪問 http://localhost:8080/John
,你會看到:
Hello from Actix using Tera!
Welcome, John!
實際畫面如圖:
這樣我們就成功地透過 URL 動態與GET request傳遞參數給模板,帶入到 HTML 頁面內使用。
在這篇文章中,我們介紹了 Actix,Actix 在大量並行的應用場景下特別有效,例如即時通訊應用、大型多人線上遊戲伺服器或需要處理大量 API 請求的微服務架構。這是因為 Actix 能夠利用 Actor 模型和非同步特性,輕鬆處理大量的並行請求而不會阻塞主執行緒。
我們首先從一個簡單的 Web 應用範例開始,展示如何使用 Actix 創建一個基本的伺服器,處理 HTTP 請求,並回傳靜態文本。接著,我們進一步討論了如何整合 Tera 模板引擎,來動態生成 HTML 頁面。透過模板,我們能夠輕鬆地將資料嵌入到網頁中,實現動態內容的呈現。
最後,我們演示了如何讓 Actix 的路由處理動態參數,透過 URL 傳遞變數到模板,生成不同的網頁內容。
HttpServer
和 App
設定路由,處理來自特定路徑的 GET 請求,並返回靜態或動態生成的內容。async
來啟用非同步特性,以提升伺服器的效能。這篇文章讓我們對於 Actix 先有一個基礎概念,這將有助於我們介紹後續的 Restful API 與其他進階應用。